package work.linruchang.oauthclientproject.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.json.JSONUtil;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * Token处理的工具
 * 根据<a href="https://jwt.io/introduction"></a> 进行构建标准Token
 * @author LinRuChang
 * @version 1.0
 * @date 2022/08/06
 * @since 1.8
 **/
public class MyTokenUtil {

    private static Dict HEADER = Dict.create();

    static {
        //签名算法可以是HS256 或者 RSA 我这里写死成HS256算法
        HEADER.set("alg", "HS256")
                .set("typ", "JWT");
    }

    private static Dict DEFAULT_PAYLOAD = Dict.create();

    static {
        DEFAULT_PAYLOAD.set("iss", "发行系统：mybaits-plus-join项目")
                .set("exp", null)  //过期时间  毫秒
                .set("cre", null) //创建时间 毫秒
                .set("sub ", "可访问资源：系统任何资源都可访问")
                .set("aud", "授权给谁：超级管理员");
    }


    /**
     * 签名密钥
     */
    private static final String secret = "sdfsdfds";


    /**
     * 生成token
     *
     * @param payload 负载
     * @return
     */
    public static String createToken(Dict payload) {
        Dict allPayload = new Dict(DEFAULT_PAYLOAD);
        if (CollUtil.isNotEmpty(payload)) {
            allPayload.putAll(payload);
        }
        if(ObjectUtil.isEmpty(allPayload.get("cre"))) { //创建时间
            allPayload.put("cre", new Date().getTime());
        }


        String HEADERJson = JSONUtil.toJsonStr(HEADER);
        String HEADERJson_Base64Url = Base64.encodeUrlSafe(HEADERJson);

        String allPayloadJson = JSONUtil.toJsonStr(allPayload);
        String allPayload_Base64Url = Base64.encodeUrlSafe(allPayloadJson);

        HMac mac = new HMac(HmacAlgorithm.HmacSHA256, secret.getBytes());
        String signSouceContent = StrUtil.format("{}.{}", HEADERJson_Base64Url, allPayload_Base64Url);
        String signature = mac.digestBase64(signSouceContent, true);

        return StrUtil.format("{}.{}.{}", HEADERJson_Base64Url, allPayload_Base64Url, signature);
    }



    /**
     * 校验token
     *  签名匹配且未过期
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        List<String> splitContent = StrUtil.split(token, ".");

        boolean verifyFlag = false;
        if (CollUtil.size(splitContent) == 3) {
            String HEADERJson_Base64Url = splitContent.get(0);
            String allPayload_Base64Url = splitContent.get(1);
            String signature = splitContent.get(2);

            //系统根据前面头信息以及负载生成签名
            HMac mac = new HMac(HmacAlgorithm.HmacSHA256, secret.getBytes());
            String systemSignSourceContent = StrUtil.format("{}.{}", HEADERJson_Base64Url, allPayload_Base64Url);
            String systemSignature = mac.digestBase64(systemSignSourceContent, true);

            //比对签名
            if (StrUtil.equals(systemSignature, signature)) {
                String allPayloadJson = Base64.decodeStr(allPayload_Base64Url);
                Dict dict = JSONUtil.toBean(allPayloadJson, Dict.class);
                String exp = dict.getStr("exp");

                //比对token有效期
                if (StrUtil.isBlank(exp) || (exp != null && new Date().getTime() < dict.getLong("exp"))) {
                    verifyFlag = true;
                }
            }
        }
        return verifyFlag;
    }

    /**
     * 获取负载信息
     * @param token
     * @return
     */
    public static Dict parse(String token) {
        if (verify(token)) {
            String allPayloadJson = Base64.decodeStr(StrUtil.split(token, ".").get(1));
            return JSONUtil.toBean(allPayloadJson, Dict.class);
        }
        return null;
    }


    /**
     * 根据Bearer认证标准从用户请求中获取token <a href=“https://datatracker.ietf.org/doc/html/rfc6750”></a>
     * @return
     */
    public static String getCurrentRequestToken()  {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String authorization = request.getHeader("Authorization");
        String token = null;

        //请求头
        if(StrUtil.isNotBlank(authorization)) {
            List<String> authorizationInfos = StrUtil.splitTrim(authorization, StrUtil.SPACE);
            if(CollUtil.size(authorizationInfos) == 2 && StrUtil.equals(authorizationInfos.get(0), "Bearer")) {
                token = authorizationInfos.get(1);
            }
        } else if(StrUtil.equalsIgnoreCase(request.getMethod(),"GET") || (StrUtil.equalsIgnoreCase(request.getMethod(),"POST") && StrUtil.containsIgnoreCase(request.getHeader("Content-Type"),"application/x-www-form-urlencoded"))) {
            token = request.getParameter("access_token");
        }

        return Optional.ofNullable(token)
                .orElse(null);
    }


    public static void main(String[] args) {
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiLlj5HooYzns7vnu5_vvJpteWJhaXRzLXBsdXMtam9pbumhueebriIsInN1YiAiOiLlj6_orr_pl67otYTmupDvvJrns7vnu5_ku7vkvZXotYTmupDpg73lj6_orr_pl64iLCJhdWQiOiLmjojmnYPnu5nosIHvvJrotoXnuqfnrqHnkIblkZgiLCJ1c2VyTmFtZSI6ImxyYyJ9._Au456JLDQ4yIlkBYo8xiHTklrn1b2AMp46KHuKrfIU";
        boolean verify = verify(token);
        Dict parseInfo = parse(token);
        Console.log(verify);
        Console.log(parseInfo);
    }

}
